iT邦幫忙

0

Javascript 進階 11-1 為什麼需要 Promise

  • 分享至 

  • xImage
  •  

今天要來介紹為什麼要使用 Promise

Promise 的使用時機就是適合來解決非同步的事件,非同步的事件通常都是 ajax 的事件,但其實除了 ajax 以外還有其他的喔~!

例如說 setTimeout 也是一種非同步事件,不過還是以大家最熟悉的 ajax 事件來進行說明~!

const url = 'https://randomuser.me/api/'; 

$.ajax({
    url: url
}).done(function (res) {
    console.log(res);
});

可以看到這個是很簡易的 jQuery ajax 的寫法,我只有撰寫了 url 向遠端位置請求資料,然後再把資料印出來!

當然 jQuery 官網也有很多種寫法~例如 直接在屬性中添加 success 屬性的,或是加入不同的 Content-Type 的等等。

$.ajax({
  url: 'https://randomuser.me/api/',
  dataType: 'json',
  success: function(data) {
    console.log(data);
  }
});

但目的都是為了從遠端取得資料回來~

那麼我們再來看看關注現在要打的這隻 API 是做甚麼~

https://ithelp.ithome.com.tw/upload/images/20200525/20121770ENEx7WbI7e.png

https://ithelp.ithome.com.tw/upload/images/20200525/20121770MbN8HxbyPc.png

很明顯,這個就是你針對他們的 API 要資料以後,他會回傳給你 result 的 json 格式資料。

內容就如同他們官網的顯示,會隨機產生使用者資料給你。

那我們實際來執行看看!

https://ithelp.ithome.com.tw/upload/images/20200525/20121770B38PUvhZYD.png

的確就跟預期的一樣!有出現官網上所說的資料格式~

狀況1

那麼現在我們來修改一下程式碼~變成下面這樣

const url = 'https://randomuser.me/api/'; 

let data = {};

$.ajax({
    url: url,
}).done(function (res) {
    console.log(res);
    data = res.results;
});

console.log(data);

各位覺得 data 的資料會是怎麼樣呢?

答案:

https://ithelp.ithome.com.tw/upload/images/20200525/20121770HicssAMDeD.png

答案就是還是維持空物件喔!

原因很簡單,因為非同步的事件會先放到事件佇列,等其他同步的程式碼執行完之後,再依順序執行。

所以這邊 ajax 事件雖然有先放到事件佇列中,但還沒跟遠端取回資料,自然就還沒有辦法再最後面的 log 給印出來。

那麼要如何才能正確印出來呢?

最快速簡單的做法就是把 log 移進去 done 的 function Block 裡面。

const url = 'https://randomuser.me/api/'; 
        
let data = {};

$.ajax({
    url: url,
}).done(function (res) {
    console.log(res);
    data = res.results;
    console.log(data);
});

https://ithelp.ithome.com.tw/upload/images/20200525/20121770GjPQYMxxdJ.png

各位也可以練習看看這樣子的寫法喔!

那其實這樣寫,每次重新整理阿

你會發現都會取得隨機不同的資料,如果我希望再取得第一次資料以後,又再取得同一個人的資料的話該怎麼半呢?

我們可以看到他的官方文件中,有一個可以帶入 seed 的參數,也就是每一筆使用者資料,都有一個特定的 seed 參數。

https://ithelp.ithome.com.tw/upload/images/20200525/20121770lgWJb9G7Ak.png

狀況2

我們需要在第一次取得資料之後,又需要在執行完之後取得第二次的資料

那我們的寫法就會是~

const url = 'https://randomuser.me/api/'; 

let data = {};

$.ajax({
    url: url,
}).done(function (res) {
    console.log(res);
    data = res.results;
    const seed = res.info.seed;
    console.log('seed', seed);
    console.log('data', data);
    console.log('res', res);

    $.ajax({
        url: `${url}?seed=${seed}`,
    }).done(function (res2) {
        console.log('res2', res2);
        const res2Seed = res2.info.seed;
        console.log(seed === res2Seed);
    });
});

https://ithelp.ithome.com.tw/upload/images/20200525/20121770HdfbvdeE8i.png

好~這樣就可以完成我們的需求對吧!

但又要第三次呢?第四次呢?

發現問題了嗎? 如果我們要做特定的處理,就必須等到非同步結束以後才能進行,這樣會造成越來越多 巢狀 以及程式碼繁亂不好維護的問題!

而使用 Promise 的好處之一就是可以解決這個問題~

那這邊也來簡單介紹一下,非同步的常見問題

  1. 回呼地獄(Callback Hell)
  2. 寫法不一致
  3. 無法同時執行(jQuery 有並行的寫法,但並不直覺)

那我們使用 axios 這個 Promise 套件進行剛剛取得遠端資料的效果並同時解決 1 / 2 / 3 的問題

axios.get(url)
    .then((res) => {
        console.log(1, res);
    });

當使用 axios 的時候首先要先決定要使用 get 還是 post,之後最簡單的一樣就是只帶入 url 。

然後利用 then 這個方法去串接,確保非同步行為已經完成!

https://ithelp.ithome.com.tw/upload/images/20200525/201217700LKJiaA9uk.png

寫法一致 + 避免回呼地獄:

那麼如果要像剛剛一樣,在第一次取完以後要進行第二次非同步事件,Promise 的行為會先 return 第二次的請求開頭,並且在下一次的 then 做接收。

axios.get(url)
    .then((res) => {
        console.log(1, res);
        const seed = res.data.info.seed;
        return axios.get(`${url}?seed=${seed}`);
    })
    .then((res) => {
        console.log(2, res);
    });

https://ithelp.ithome.com.tw/upload/images/20200525/20121770274Bj7tpco.png

同時發出請求

Promise 裡面有一個 all 的語法,會同時分別針對不同的 url 進行請求,並且等到都完成拿到結果之後,在進行下一步。

Promise.all([axios.get(url), axios.get(url)])
    .then(([res1, res2]) => {
        console.log(1, res1);
        console.log(2, res2);
    });

透過陣列的方式傳入 非同步行為,並且回傳一個陣列包含兩個非同步行為的結果。

https://ithelp.ithome.com.tw/upload/images/20200525/20121770xHIJ0TqJJO.png

以上就是使用 Promise 的原因,以及一些簡單的範例介紹,如果沒有問題的話就可以繼續往後續的文章嚕!汪汪~


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言